// Slower C++ solution:
#include <iostream>

#include <stdio.h>

#include <string>

#include <cstring>

#include <cstdio>

#include <algorithm>

#include <cmath>

#include <vector>

#include <set>

#include <map>

#include <unordered_map>

#include <queue>

#include <deque>

#include <stack>

#include <bitset>

#include <iomanip>



#define ll long long

#define ld long double

#define ull unsigned long long

#define endl "\n"

#define MohamedMotaz ios::sync_with_stdio(0); cin.tie(0); ios_base::sync_with_stdio(0);

#define f(a, b, c) for(int a = b; a < c; a++)

#define fr(a, b, c) for(int a = b; a >= c; a--)

using namespace std;





//ll fact[1000001]; ll inv[1000001];

//ll primes[100007];

//ll arr[1000007];

//ll modPower(ll b, ll p) {

//	if (p == 0)

//		return 1;

//

//	ll halfpow = modPower(b, p / 2);

//	ll toReturn = (halfpow * halfpow) % mod;

//	if (p % 2)

//		toReturn = (toReturn * b) % mod;

//

//	return toReturn;

//}

//

//ll fastPower(ll b, ll p) {

//	if (p == 0)

//		return 1;

//	ll ans = fastPower(b, p / 2);

//	ans = (ans * ans);

//	if (p % 2 != 0)

//		ans = (ans * b);

//	return ans;

//}

//ll GcdRecursive(ll a, ll b) {

//	if (b == 0) return a;

//	return GcdRecursive(b, a % b);

//}

//ll modLCM(ll a, ll b) {

//	ll val = GcdRecursive(a, b);

//	ll tmp = ((a % mod) * (b % mod)) % mod;

//	ll finalVal = ((tmp % mod) * (arr[val] % mod)) % mod;

//	return finalVal;

//

//}

//ll LCM(ll a, ll b) {

//	return (a * b) / GcdRecursive(a, b);

//}

//void move1step(ll& a, ll& b, ll q) { // a and b by reference

//	ll c = a - q * b;

//	a = b;

//	b = c;

//}

//ll GcdIterative(ll a, ll b) {

//	while (b) move1step(a, b, a / b);

//	return a;

//}

//

//void pre(ll n) {

//

//	fact[0] = 1;

//	inv[0] = 1;

//

//	for (ll i = 1; i <= n; i++) {

//		fact[i] = (i * fact[i - 1]) % mod;

//		inv[i] = modPower(fact[i], mod - 2);

//		arr[i] = modPower(i, mod - 2);

//	}

//}

//

//ll npr(ll n, ll r) {

//	return ((fact[n] * inv[n - r]) % mod);

//}

//

//ll ncr(ll n, ll r) {

//	return ((((fact[n] * inv[n - r]) % mod) * inv[r]) % mod);

//}

//

//void sieve(ll val) {

//	memset(primes, 1, sizeof primes);

//	primes[0] = primes[1] = false;

//	for (int i = 2; i <= val; i++) {

//		if (primes[i]) {

//			for (int j = i * i; j <= val; j += i) {

//				primes[j] = 0;

//			}

//		}

//	}

//

//}



const ll mod = 1e9 + 7;

const ll N = 2e5 + 7;

const ll inf = 1e9 + 5;







ll n,m, a, b, ans = 0, c= 0;

vector<ll> adj[N];

bool visited[N] = {false};

ll dp[N] = {};

void dfs(ll node){





    visited[node] = true;

    for (auto elem: adj[node]){

        if (!visited[elem]) dfs(elem);

        dp[node] = max(dp[node], dp[elem] + 1);

        ans = max(ans, dp[node]);

    }





}



int main()

{

    MohamedMotaz;

    cin >> n >> m;

    f(i,0,m){

        cin >> a >> b;

        adj[a].push_back(b);

    }



    for (int i = 1; i <= n; i++) dfs(i);



    cout << ans;

}








// Faster C++ solution for the same problem (measured speedup: 1.6371789168024005x):
#include <bits/stdc++.h>



/**

       return NO_PAIN ? NO_GAIN : GAIN;

*/



using namespace std;



#define all(v)   v.begin(), v.end()

#define sz(x)    (int) x.size()

#define Unique(x) x.erase(unique(all(x)), x.end())

#define endl "\n"

#define pb push_back

#define START cin.tie(0); cout.tie(0); ios_base::sync_with_stdio(0);

#define isOdd(n)    (n&1)

#define pow(n, m) (ll)powl(n, m)

#define numOfDigits(n)  ((n)? (ll)(log10(n))+1 : 1)

#define clr(x, val)    memset(x, val, sizeof(x)) //be careful of value and TLE

#define MOD 1000000007

#define EPS 1e-7

#define LSOne(x)  (x & (-x))   //least significant 1

typedef long long ll;

typedef long double ld;

typedef pair<int, int> pii;

typedef vector<int> vi;



const int N = 1e5 + 1;

vector<vi> adj(N);

bool vis[N];

int dp[N];

void dfs(int u){

    /*

    for each vertex, ask it what is the longest path for you.

     then his parent's longest path is max + 1

    */

    vis[u] = 1;

    for(int i = 0; i<sz(adj[u]); i++){

        int v = adj[u][i];

        if(!vis[v])

            dfs(v);

        dp[u] = max(dp[u], dp[v] + 1);

    }

}

int main()

{

    START

    //freopen("test cases\\in.txt", "r", stdin) ;

    //freopen("test cases\\in.txt", "w", stdout);

    int n, m; cin>>n>>m;



    for(int i = 0; i<m; i++){

        int u, v; cin>>u>>v;

        adj[u].pb(v);

    }

    int mx = 0;

    for(int i = 1; i<=n; i++)

        if(!vis[i] && sz(adj[i]))

            dfs(i);



    cout<<*max_element(dp, dp+N);

	return 0;

}